home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
yerk
/
mps231ss.hqx
/
Mops source
/
Nuc source
/
Nuc2.asm
< prev
next >
Wrap
Assembly Source File
|
1993-02-25
|
66KB
|
3,630 lines
; Now we set up for the first word in the dictionary:
d
q0 set 0
q1 set 0
q2 set 0
q3 set 0
q4 set 0
q5 set 0
q6 set 0
q7 set 0
; Note: the first link field must not be located at d. So we put a few other things
; before the first header.
; ======================================
; OBJECTS, CONSTANTS, VALUES etc.
; ======================================
FreeHeap long ; Used during setup
ExpDicq byte ; Set while we're expecting a dic image
DicRead byte ; Set when we've just read one
RAinMod byte ; Set if a relocatable address is in a module
ErrInfoValid
byte ; Set if there's valid saved error info
align
; Many system objects are up in the overlap area. We just define
; their _t codes here.
fWind_t set doObj
fEvent_t set doObj
fpRect_t set doObj
fdRect_t set doObj
; fFcb object is now allocated in the heap - fFcb itself is an object pointer.
head 4,FFCB,fFcb,doObjPtr ; FFCB
head 5,FWIND,fWind,doObj ; FWIND
byte $9C
dc.w $F,2,$116,$1EE ; contRect
byte $2E
valu 3,TIB,tib ; TIB
valu 3,PAD,pad ; PAD
valu 8,^ERRDUMP,PtrErrDump ; ^ERRDUMP
valu 6,THERGN,TheRgn ; TheRgn
varbl 11,EXTRALOCALS,ExtraLocals ; ExtraLocals
long 20
ExtraLocalsEnd
const 6,TIBLEN,.tibln,tibLen ; TIBLEN
varbl 4,#TIB,ntib ; #TIB
long
varbl 3,>IN,toin ; >IN
long
valu 9,SRC-START,srcstart ; SRC-START
valu 7,SRC-LEN,srclen ; SRC-LEN
valu 9,SOURCE-ID,sourceID ; SOURCE-ID
valu 7,SAVEDRP,savedRP ; SavedRP
valu 3,OUT,out ; OUT
valu 5,STATE,state ; STATE
valu 6,CSTATE,cstate ; CSTATE
valu 4,BASE,nbase,10 ; BASE
valu 3,DPL,dpl ; DPL
valu 3,HLD,hld ; HLD
nvalu throwHandler ; ThrowHandler
nvalu DotStkLim,$7FFFFFFF ; DotStkLim
valu 10,SLEEPTICKS,sleepTicks,-1 ; SLEEPTICKS
valu 5,MMRGN,MMRgn,0 ; MMRGN
valu 7,EXBOFFS,exBoffs ; EXBOFFS
valu 7,MROPEN?,.MRopen,0 ; MROPEN?
valu 7,INSTLD?,instldq,0 ; INSTLD?
valu 8,INITZED?,itzed,0 ; INITZED?
valu 8,QUITAPP?,QuitAppq,0 ; QUITAPP?
valu 6,FWIND?,fWindq,-1 ; FWIND?
valu 9,WNEAVAIL?,WNEavail,0 ; WNEavail?
valu 9,HWPAVAIL?,HWPavail ; HWPavail?
valu 13,GESTALTAVAIL?,GestaltAvail ; GestaltAvail?
valu 12,APPLEEVENTS?,AppleEventsQ ; AppleEvents?
valu 6,(ERR#),pErrNum,0 ; (Err#)
valu 11,#DOCSTOOPEN,NumDocsToOpen ; #docsToOpen
valu 4,FPU?,FPUq ; FPU?
valu 6,SAMASK,SAmask ; SAmask
valu 9,PROCESSOR,processor ; PROCESSOR
valu 6,MAXDIC,MaxDic,300000 ; MAXDIC
valu 7,MINHEAP,MinHeap,20000 ; MINHEAP
valu 7,DICSIZE,dicsize ; DICSIZE
valu 8,STKSPACE,stkSpace,50000 ; STKSPACE
valu 9,RSTKSPACE,RstkSpace,6000 ; RSTKSPACE
valu 3,SP0,sp0 ; SP0
valu 3,RP0,rp0 ; RP0
valu 4,LOC#,locno ; LOC#
valu 2,#P,numP ; #P
valu 3,#PL,numPL ; #PL
valu 2,#F,numF ; #F
valu 6,FLTFLG,FltFlg ; fltFlg
valu 6,LOCAL?,localq,0 ; local?
valu 7,METHOD?,methodq,0 ; method?
valu 8,SELFREF?,selfRefq ; selfref?
valu 8,OBJCLASS,objClass ; objClass
valu 4,#1ST,num1st ; #1st
valu 5,#LAST,numLast ; #Last
valu 7,HELDMOD,heldMod ; HeldMod
long ; (extra location to save old A5 while a module is held)
valu 9,METHINDEX,MethIndex ; MethIndex
valu 6,MBCOMP,MBcomp ; MBcomp
valu 7,SACOMP?,SAcomp ; SAcomp?
valu 9,RELOCCHK?,RelocChkq,-1 ; RelocChk?
valu 10,INHIBITMB?,inhibitMBq ; InhibitMB?
valu 7,COMPMOD,compMod ; CompMod
; The following 8 values will be set by the floating point code, to the
; addresses of the corresponding words, FPDisp etc. These addresses are
; used by Handlers to compile calls to the corresponding words.
valu 7,^FPDISP,ptrFPdisp,-1 ; ptrFPdisp
valu 8,^FPDISP2,ptrFPdisp2,-1 ; ptrFPdisp2
valu 6,^FPNEW,ptrFPnew,-1 ; ptrFPnew
valu 7,^FPULIT,ptrFPULit,-1 ; ptrFPULit
valu 7,^LFLOAT,ptrLfloat,-1 ; ptrLfloat
valu 9,^TOLFLOAT,ptrToLfloat,-1 ; ptrToLfloat
valu 7,^TOFVAL,ptrToFval,-1 ; ptrToFval
valu 7,^LFDISP,ptrLFdisp,-1 ; ptrLFdisp
const 2,BL,bl,32 ; BL
const 4,TRUE,true,-1 ; TRUE
const 5,FALSE,false,0 ; FALSE
const 8,#THREADS,nthreads,8 ; #THREADS
const 4,BIG#,bigno,$7FFFFFFF ; BIG#
; Some handler code values that we need to be able to access from
; above the nucleus:
const 9,CLASSCODE,.classCode,class_h ; CLASSCODE
const 7,OBJCODE,.objCode,obj_h ; OBJCODE
const 8,FVALCODE,.FvalCode,Fval_h ; FVALCODE
const 4,NILH,nilH,$FFA00101 ; NILH
const 4,NILP,nilP,$FFA00103 ; NILP
nvalu diskErr,0 ; DISK-ERROR
valu 4,CURS,curs,-1 ; CURS
valu 6,UCFLAG,ucflag,-1 ; UCFLAG
valu 4,OPT?,optq,-1 ; OPT?
const 5,INLMK,inlMk,$4AFC ; INLMK
currBase
byte
fmkCnt byte
callOut byte
CCmpFlg byte
colAflg byte
align
ODaddr long
TempPtr ptr
Temp byte 20 ; This gets used for a few things.
; =============================
; SYSTEM VECTORS
; =============================
; First, some non-in-line versions of any words that are needed
; for vectors. A word assigned to a vector must be able to be JSR'd to.
head 6,VFALSE,vfalse ; VFALSE
parms false
rts
; That was the only one!!
svec 7,EMITVEC,emitvec,pemit ; EMITVEC
svec 8,PEMITVEC,pemitvec,drop ; PEMITVEC
svec 5,CRVEC,crvec,pcr ; CRVEC
svec 6,PCRVEC,pcrvec ; PCRVEC
svec 7,TYPEVEC,typevec,ptype ; TYPEVEC
svec 8,PTYPEVEC,ptypevec,twodrop ; PTYPEVEC
svec 7,ECHOVEC,echovec,pemit ; ECHOVEC
svec 6,HEADER,header,pheader ; HEADER
svec 6,LOGVEC,logvec ; LOGVEC
; ==================================
semis_m macrox
RTS
endm
nohead semis,inline ; ;S
pexit_m macrox
RTS
endm
head 6,(EXIT),pexit,inline ; (EXIT)
; DO loops
DO_M macrox &1
LEA &1,A1
JSR DoSetup-base(A3)
endm
QDO_M macrox &1
LEA &1,A1
JSR QDoSetup-base(A3)
endm
DoSetup
MOVE.L (A7),A0 ; Save rtn addr
MOVE.L D3,(A7) ; Save old i
MOVE.L (A6)+,D3 ; New i
MOVE.L A1,-(A7) ; LEAVE address
MOVE.L (A6)+,-(A7) ; Limit
JMP (A0) ; Return
QDoSetup
MOVE.L A6,A0 ; Copy of data stk ptr to A0
CMPM.L (A0)+,(A0)+ ; Compare index, limit
BGT.S DoSetup ; Limit greater - continue with loop
ADDQ #8,A6 ; LE - skip loop - drop index and limit
ADDQ #4,A7 ; and return address
JMP (A1) ; And jump instead to after (+)LOOP code
LOOP_M macrox &1
ADDQ.L #1,D3
CMP.L (A7),D3
BLT &1
ADDQ.L #8,A7
MOVE.L (A7)+,D3
endm
PlLoop_M macrox &1
POP.L D0
BPL.S .up
ADD.L D0,D3
MOVE.L (A7),D0
SUBQ.L #1,D0
CMP.L D3,D0
BRA.S .tst
.up ADD.L D0,D3
CMP.L (A7),D3
.tst BLT &1
ADDQ.L #8,A7
MOVE.L (A7)+,D3
endm
PlLpD_M macrox &1
BPL.S .up
ADD.L D0,D3
MOVE.L (A7),D0
SUBQ.L #1,D0
CMP.L D3,D0
BRA.S .tst
.up ADD.L D0,D3
CMP.L (A7),D3
.tst BLT &1
ADDQ.L #8,A7
MOVE.L (A7)+,D3
endm
plLpUp_m macrox &1
CMP.L (A7),D3
BLT &1
ADDQ.L #8,A7
MOVE.L (A7)+,D3
endm
PlLpDn_m macrox &1
CMP.L (A7),D3
BGE &1
ADDQ.L #8,A7
MOVE.L (A7)+,D3
endm
windupDo
ADDQ.L #8,A7
MOVE.L (A7)+,D3
doLeave ADDQ.L #4,A7 ; Pop limit
MOVE.L (A7)+,A0 ; Loop end addr to A0 so we can go there
MOVE.L (A7)+,D3 ; Restore old i
JMP (A0) ; Goto loop end
pdo_m macrox
do_m dummylab
endm
pqdo_m macrox
qdo_m dummylab
endm
ploop_m macrox
loop_m dummylab
endm
pplloop_m macrox
plLoop_m dummylab
endm
ppLpD_m macrox
PlLpD_m dummylab
endm
ppLpUp_m macrox
plLpup_m dummylab
endm
ppLpDn_m macrox
plLpDn_m dummylab
endm
loc
nohead pdo,inline ; (do)
loc
nohead pqdo,inline ; (?do)
loc
nohead ploop,inline ; (loop)
loc
nohead pplloop,inline ; (+loop)
loc
nohead ppLpD,inline
loc
nohead ppLpUp,inline
loc
nohead ppLpDn,inline
loc
word
; These are called e.g. by
; compyl pdo
; followed by an adjustment so that >MARK etc. can be used to
; set up the branches.
dummyLab
_Debugger
; DoNoOpt is called by the NoOpt macro.
DoNoOpt PUSH.L A0 ; Save A0 - anything might be going on!
MOVE.L ODaddr,A0
CLR.W (A0)
POP.L A0 ; Restore A0
RTS
; DoSavA5 is called by the SavA5 macro.
head 7,DOSAVA5,DoSavA5
move.l (a7),a1 ; Rtn addr to A1 (FCB words use A0!)
move.l a5,(a7) ; Save A5 on return stack
move.l a7,savedRP-base(a3) ; Save RP for :PROC
move.l CurrentA5,a5 ; Set A5 and SP to what the system expects
exg a6,a7
jmp (a1)
; ============ A few miscellaneous items ============
myRegs long 4 ; Saves Mops' A3-A5 and A7, for :PROC.
ChkLim word ; Used in limit checking
; Some quantities we need in handling AppleEvents.
;fAE long
AEReply long
AERefCon long
; ======== Dictionary header address conversion ========
head 8,TRAVERSE,traverse ; TRAVERSE
bra doTraverse
NtoLink_m macrox
SUBQ.L #4,(A6)
endm
head 6,N>LINK,NtoLink,inline ; N>LINK
LtoName_m macrox
ADDQ.L #4,(A6)
endm
head 6,L>NAME,LtoName,inline ; L>NAME
head 5,NAME>,namefrom ; NAME>
n 1
parms traverse
ADDQ.L #3,(A6)
parms semis
head 5,LINK>,linkfrom ; LINK>
parms LtoName,namefrom,semis
head 5,>BODY,tobody ; >BODY
MOVE.L (A6),A0
MOVE.W -2(A0),D0 ; Handler addr to D7 (word)
MOVEQ #0,D1
MOVE.W -2(A3,D0.W),D1 ; >body offset to D0
ADD.L D1,(A6)
next
head 5,>NAME,toName ; >NAME
SUBQ.L #3,(A6)
n -1
parms traverse,semis
head 5,>LINK,toLink ; >LINK
parms toName,NtoLink,semis
head 4,>HDLR,toHdlr ; >HDLR
subq.l #2,(A6)
rts
; ========================
; STACK MANIPULATION
; ========================
drop_m macrox
ADDQ.L #4,A6
endm
head 4,DROP,drop,inline ; DROP
twoDrop_m macrox
ADDQ.L #8,A6
endm
head 5,2DROP,twoDrop,inline ; 2DROP
nip_m macrox
POP.L (A6)
endm
head 3,NIP,nip,inline,tsCCOK ; NIP
swap_m macrox
pop.l d0
move.l (a6),d1
move.l d0,(a6)
push.l d1
endm
head 4,SWAP,swap,xinfo,,swap_h ; SWAP
dc.w otSWAP*256
use swap
dup_m macrox
PUSH.L (A6)
endm
head 3,DUP,dup,inline,tsdup ; DUP
head 4,2DUP,twoDup,docode,tsCCOK ; 2DUP
PUSH.L 4(A6)
PUSH.L 4(A6)
RTS
qdup_m macrox
TST.L (A6)
BEQ.S .end
PUSH.L (A6)
.end
endm
head 4,?DUP,qdup,inline,tsCCok ; ?DUP
zdup_m macrox
TST.L (A6)
BNE.S .end
PUSH.L (A6)
.end
endm
head 4,0DUP,zdup,inline,tsCCok ; 0DUP
over_m macrox
PUSH.L 4(A6)
endm
head 4,OVER,over,inline,otOver*256 ; OVER
head 4,TUCK,tuck,docode,tsCCOK ; TUCK
pop.l d0
move.l (a6),d1
move.l d0,(a6)
push.l d1
push.l d0
rts
head 3,ROT,rot,docode,tsCCOK ; ROT
movem.l (a6)+,d1/d2/a0
move.l a0,d0
movem.l d0-d2,-(a6)
rts
head 4,DOWN,down ; DOWN
movem.l (a6)+,d0-d2
move.l d0,a0
movem.l d1/d2/a0,-(a6)
rts
head 4,PICK,pick,docode,tsCCOK ; PICK
move.l (a6),d0
asl.l #2,d0
move.l 4(a6,d0.w),(a6)
rts
; =============================
; SIMPLE ARITHMETIC
; =============================
plus_m macrox
POP.L D0
ADD.L D0,(A6)
endm
head 1,+,plus,xinfo,,pm_h ; +
dc.w otADD
use plus
minus_m macrox
POP.L D0
SUB.L D0,(A6)
endm
head 1,-,minus,xinfo,,pm_h ; -
dc.w otSUB
use minus
head 3,MAX,max ; MAX
POP.L D0
CMP.L (A6),D0
BLT.S .end
MOVE.L D0,(A6)
.end NEXT
head 3,MIN,min ; MIN
POP.L D0
CMP.L (A6),D0
BGT.S .end
MOVE.L D0,(A6)
.end NEXT
negate_m macrox
NEG.L (A6)
endm
head 6,NEGATE,negate,xinfo,,pm_h ; NEGATE
dc.w otNEG
use negate
head 2,+-,plmin ; +-
TST.L (A6)+
BPL.S .end
doneg NEG.L (A6)
.end RTS
head 3,ABS,abs ; ABS
TST.L (A6)
BMI.S doneg
RTS
head 7,ALIGNED,aligned ; ALIGNED
; ( n -- n' )
moveq #1,d0
and.l (a6),d0
add.l d0,(a6)
rts
head 6,EXTEND,extend ; EXTEND
move.l (a6),d0
ext.l d0
move d0,(a6)
rts
head 3,S>D,StoD ; S>D
tst.l (a6)
smi d0
ext.w d0
ext.l d0
push.l d0
rts
; Increments, decrements etc. These are defined here as macros, only for the
; nucleus itself. In the file Base they are defined properly as immediate words
; so our optimization can deal with them.
onep_m macrox
ADDQ.L #1,(A6)
endm
nohead onep,inline ; 1+
twop_m macrox
ADDQ.L #2,(A6)
endm
nohead twop,inline ; 2+
threep_m macrox
ADDQ.L #3,(A6)
endm
nohead threep,inline ; 3+
fourp_m macrox
ADDQ.L #4,(A6)
endm
nohead fourp,inline ; 4+
onem_m macrox
SUBQ.L #1,(A6)
endm
nohead onem,inline ; 1-
twom_m macrox
SUBQ.L #2,(A6)
endm
nohead twom,inline ; 2-
threem_m macrox
SUBQ.L #3,(A6)
endm
nohead threem,inline ; 3-
fourm_m macrox
SUBQ.L #4,(A6)
endm
nohead fourm,inline ; 4-
twostar_m macrox
MOVE.L (A6),D0
ADD.L D0,(A6)
endm
head 2,2*,twostar,inline ; 2*
twosl_m macrox
MOVE.L (A6),D0
ASR.L #1,D0
MOVE.L D0,(A6)
endm
head 2,2//,twosl,inline ; 2/
; =======================
; LOGICAL OPERATIONS
; =======================
; NOT and INVERT are synonyms.
znot_m macrox
NOT.L (A6)
endm
head 3,NOT,znot,xinfo,,pm_h ; NOT
dc.w otNOT
use znot
invert_m macrox
not.l (a6)
endm
head 6,INVERT,invert,xinfo,,pm_h ; INVERT
dc.w otNOT
use invert
zand_m macrox
POP.L D0
AND.L D0,(A6)
endm
head 3,AND,zand,xinfo,,pm_h ; AND
dc.w otAND
use zand
zor_m macrox
POP.L D0
OR.L D0,(A6)
endm
head 2,OR,zor,xinfo,,pm_h ; OR
dc.w otOR
use zor
xor_m macrox
POP.L D0
EOR.L D0,(A6)
endm
head 3,XOR,xor,xinfo,,pm_h ; XOR
dc.w otEOR
use xor
; Logical operations directly on a memory byte
head 4,CSET,cset ; CSET
; ( c addr -- ) ORs c into the byte at addr.
POP.L A0
POP.L D0
OR.B D0,(A0)
RTS
head 6,CRESET,creset ; CRESET
; ( c addr -- ) Clears bits in byte at addr, corresponding
; to the bits SET in c.
POP.L A0
POP.L D0
NOT.B D0
AND.B D0,(A0)
RTS
head 7,CTOGGLE,ctoggle ; CTOGGLE
; ( c addr -- ) Exclusive-ORs c into the byte at addr.
POP.L A0
POP.L D0
EOR.B D0,(A0)
RTS
head 8,CREPLACE,creplace ; CREPLACE
; ( c mask addr -- )
; Replaces bits in the addressed byte with the corresponding
; bits from c, in those positions where the mask has ones.
POP.L A0
POP.L D1 ; Mask to D1
POP.L D0 ; c to D0
AND.B D1,D0
NOT.B D1
AND.B D1,(A0) ; Clear masked bits in addressed byte
OR.B D0,(A0) ; Set where set in c
RTS
; Logical operations on a memory bit. These operations all designate
; the operand bit by means of an address and a bit number. The bit number
; can be greater than 8, and this just takes us to successive bytes to the
; left. It seems more logical for the bit number to follow the address,
; even though this apparently is inconsistent for the operand ordering
; in CSET etc. But this isn't a real inconsistency, since the bit number
; is really an extension of the address, not a separate data item.
getbit pop.l d0
pop.l a0
move.w d0,d1
lsr.w #3,d1
sub.w d1,a0
rts
head 4,BSET,.bset,xinfo,,bit_h ; BSET
; ( addr n -- ) Sets the bit.
dc.w tsBset
.bset bsr.s getbit
bset d0,(a0)
rts
head 6,BRESET,.breset,xinfo,,bit_h ; BRESET
; ( addr n -- ) Clears the bit.
dc.w tsBreset
.breset bsr.s getbit
bclr d0,(a0)
rts
head 7,BTOGGLE,.btoggle,xinfo,,bit_h ; BTOGGLE
; ( addr n -- ) Toggles the bit.
dc.w tsBtoggle
.btoggle bsr.s getbit
bchg d0,(a0)
rts
head 5,BTEST,.btest,xinfo,,bit_h ; BTEST
; ( addr n -- b )
dc.w tsBtest
.btest bsr.s getbit
btst d0,(a0)
bne.s setTrue
bra.s setFalse
; Comparisons
head 2,U<,ult ; U<
xcmp CMPM.L (A6)+,(A6)+
BLO.S setTrue
BRA.S setFalse
head 2,U>,ugt ; U>
CMPM.L (A6)+,(A6)+
BHI.S setTrue
BRA.S setFalse
head 1,<,lt,docode,tsLT ; <
CMPM.L (A6)+,(A6)+
BLT.S setTrue
BRA.S setFalse
head 1,>,gt,docode,tsGT ; >
CMPM.L (A6)+,(A6)+
BGT.S setTrue
BRA.S setFalse
head 1,=,eq,docode,tsEQ ; =
CMPM.L (A6)+,(A6)+
BNE.S setFalse
setTrue MOVEQ #-1,D0
PUSH.L D0
RTS
head 2,<>,ne,docode,tsNE ; <>
CMPM.L (A6)+,(A6)+
pushBool
BNE.S setTrue
setFalse
CLR.L -(A6)
RTS
head 2,>=,ge,docode,tsGE ; >=
CMPM.L (A6)+,(A6)+
BGE.S setTrue
BRA.S setFalse
head 2,<=,le,docode,tsLE ; <=
CMPM.L (A6)+,(A6)+
BLE.S setTrue
BRA.S setFalse
head 2,0=,zeq,docode,tsZEQ ; 0=
xtst TST.L (A6)+
BEQ.S setTrue
BRA.S setFalse
head 3,0<>,zne,docode,tsZNE ; 0<>
TST.L (A6)+
BNE.S setTrue
BRA.S setFalse
head 2,0<,zlt,docode,tsZLT ; 0<
TST.L (A6)+
BLT.S setTrue
BRA.S setFalse
head 2,0>,zgt,docode,tsZGT ; 0>
TST.L (A6)+
BGT.S setTrue
BRA.S setFalse
head 3,0<=,zle,docode,tsZLE ; 0<=
TST.L (A6)+
BLE.S setTrue
BRA.S setFalse
head 3,0>=,zge,docode,tsZGE ; 0>=
TST.L (A6)+
BGE.S setTrue
BRA.S setFalse
head 7,WITHIN?,within,docode,tsCCOK ; WITHIN?
; ( n lo hi -- n b ) Returns true if lo <= n <= hi.
POP.L D1 ; D1 = hi
POP.L D0 ; D0 = lo
MOVEQ #0,D2 ; D2 for return result
CMP.L (A6),D0
BGT.S .end
CMP.L (A6),D1
BLT.S .end
MOVEQ #-1,D2
.end PUSH.L D2
RTS
; ===========================
; FETCHES AND STORES
; ===========================
at_m macrox
move.l (a6),a0
move.l (a0),(a6)
endm
head 1,@,at,xinfo,,at_h ; @
dc.w tsAT
dc.w 0
use at
head 4,>PTR,.toptr,xinfo,,at_h ; >PTR
; In our system, this is an alias for @.
dc.w tsAT
dc.w 0
.toptr bra.s at
wat_m macrox
MOVE.L (A6),A0
MOVEQ #0,D0
MOVE.W (A0),D0
MOVE.L D0,(A6)
endm
head 2,W@,wat,xinfo,,at_h ; W@
dc.w tsWAT
dc.w 0
use wat
watx_m macrox
MOVE.L (A6),A0
MOVE.W (A0),A1 ; Sign-extends
MOVE.L A1,(A6)
endm
head 3,W@X,watx,xinfo,,at_h ; W@X
dc.w tsWAT
dc.w fbExt
use watx
cat_m macrox
MOVE.L (A6),A0
MOVEQ #0,D0
MOVE.B (A0),D0
MOVE.L D0,(A6)
endm
head 2,C@,cat,xinfo,,at_h ; C@
dc.w tsCAT
dc.w 0
use cat
catx_m macrox
move.l (a6),a0
move.b (a0),d0
ext.w d0
ext.l d0
move.l d0,(a6)
endm
head 3,C@X,catx,xinfo,,at_h ; C@X
dc.w tsCAT
dc.w fbExt
use catx
store_m macrox
POP.L A0
MOVE.L (A6)+,(A0)
endm
head 1,!,store,xinfo,,store_h ; !
dc.w otStore*256 + Lcode
use store
plstore_m macrox
POP.L A0
POP.L D0
ADD.L D0,(A0)
endm
head 2,+!,plstore,xinfo,,store_h ; +!
dc.w otADD*256 + Lcode
use plstore
mnstore_m macrox
POP.L A0
POP.L D0
SUB.L D0,(A0)
endm
head 2,-!,mnstore,xinfo,,store_h ; -!
dc.w otSUB*256 + Lcode
use mnstore
wstore_m macrox
pop.l a0
addq #2,a6
move.w (a6)+,(a0)
endm
head 2,W!,wstore,xinfo,,store_h ; W!
dc.w otStore*256 + Wcode
use wstore
wplstore_m macrox
pop.l a0
pop.l d0
add.w d0,(a0)
endm
head 3,W+!,wplstore,xinfo,,store_h ; W+!
dc.w otADD*256 + Wcode
use wplstore
wmnstore_m macrox
pop.l a0
pop.l d0
sub.w d0,(a0)
endm
head 3,W-!,wmnstore,xinfo,,store_h ; W-!
dc.w otSUB*256 + Wcode
use wmnstore
cstore_m macrox
POP.L A0
POP.L D0
MOVE.B D0,(A0)
endm
head 2,C!,cstore,xinfo,,store_h ; C!
dc.w otStore*256 + Ccode
use cstore
; ==============================
; RETURN STACK OPERATIONS
; ==============================
; Note: we keep the loop index I in D3, but the return stack is entirely
; in memory so that words can be called simply with BSR/JSR. This means that
; I can be used in words called from within DO loops. In fact I can be used
; as another local variable.
i_m macrox
PUSH.L D3
endm
head 1,I,i,xinfo,,reg_h ; I
dc.b mdDn
dc.b 3
use i
j_m macrox
PUSH.L 8(A7)
endm
head 1,J,j,inline ; J
k_m macrox
PUSH.L 20(A7)
endm
head 1,K,k,inline ; K
tor_m macrox
POP.L -(A7)
endm
head 2,>R,toR,inline ; >R
rfrom_m macrox
PUSH.L (A7)+
endm
head 2,R>,Rfrom,inline ; R>
; R and R@ are synonyms.
r_m macrox
push.l (a7)
endm
head 1,R,r,inline ; R
rat_m macrox
push.l (a7)
endm
head 2,R@,rat,inline ; R@
ptrBase_m macrox
PUSH.L A2
endm
head 5,^BASE,ptrBase,xinfo,,reg_h ; ^BASE
dc.b mdAn
dc.b 2
use ptrBase
head 4,SELF,.self ; SELF
; Note: SELF is not necessarily the same as ^BASE, because of multiple
; inheritance.
move.l a2,a0
subq #2,a0
add.w (a0),a0
addq #8,a0
push.l a0
rts
; =============================
; MISCELLANEOUS LOW-LEVEL WORDS
; =============================
spat_m macrox
move.l a6,-(a6)
endm
head 3,SP@,spat,xinfo,,reg_h ; SP@
dc.b mdAn
dc.b 6
use spat
spstore_m macrox
move.l (a6),a6
endm
head 3,SP!,spstore,inline ; SP!
rpat_m macrox
move.l a7,-(a6)
endm
head 3,RP@,rpat,xinfo,,reg_h ; RP@
dc.b mdAn
dc.b 7
use rpat
head 3,RP!,rpstore ; RP!
move.l (a7),a0 ; Save rtn addr
clr.l ExBoffs-base(a3)
pop.l a7
moveq #-1,d0
move.l d0,a2
jmp (a0)
head 6,BOUNDS,bounds ; BOUNDS
; ( addr cnt -- limit addr ) Equivalent to OVER + SWAP.
; Useful for setting up many DO loops.
move.l (a6),d0
move.l 4(a6),(a6)
add.l d0,4(a6)
rts
here_m macrox
fVal DP
endm
head 4,HERE,here,inline ; HERE
head 5,ALLOT,allot ; ALLOT
incVal DP
NoOpt
RTS
head 4,ROOM,room ; ROOM
parms DicSize,here
LEA start,A0
PUSH.L A0
parms minus,minus,semis
head 6,UNUSED,unused ; UNUSED
bra room
head 8,HEADROOM,.headroom ; HEADROOM
LEA 32766(A4),A0
SUB.L dp,A0
PUSH.L A0
RTS
head 3,BYE,bye,spec ; BYE
bra doBye
head 4,NULL,null,spec ; NULL
RTS
head 5,COUNT,count ; COUNT
bra doCount
head 6,LENGTH,length ; LENGTH
bra doLength
head 5,DEPTH,depth ; DEPTH
bra doDepth
head 5,DIGIT,digit ; DIGIT
bra doDigit
head 7,DECIMAL,decimal ; DECIMAL
MOVE.L #10,nbase-base(A3)
RTS
head 3,HEX,hex ; HEX
MOVE.L #16,nbase-base(A3)
RTS
head 6,W@(IP),.watIP ; W@(IP)
bra doWatIP
head 5,@(IP),.atIP ; @(IP)
bra doAtIP
; HASH now produces a 32-bit hash value. We always set the top bit
; (so that a hashed value is never zero, and is always distinguishable
; from a relocatable address, which is always "positive").
; This means that we effectively have 2**31 hash possibilities. This is
; large enough that hash collisions will hardly ever occur.
; If a 16-bit hash value is required, as in Neon, use wHash.
head 4,HASH,.hash ; HASH
; ( addr -- n )
bra doHash
head 5,WHASH,.wHash ; wHASH
bra doWhash
head 5,^ELEM,elem ; ^ELEM
; ( index -- addr ) A2 is ^obj. Leaves addr of indexed element.
bra doElem
head 6,^ELEM1,.elem1 ; ^ELEM1
; ( index -- ) As for ^ELEM, but assumes width = 1. Saves multiplying.
bra doElem1
head 6,^ELEM2,.elem2 ; ^ELEM2
bra doElem2
head 6,^ELEM4,.elem4 ; ^ELEM4
bra doElem4
head 7,IDXBASE,idxbase ; IDXBASE
bra doIdxBase
head 5,LIMIT,.limit ; LIMIT
bsr doIdxBase
move.l d1,(a6)
rts
lobase_m macrox
push.l a3
endm
hibase_m macrox
push.l a4
endm
modbase_m macrox
push.l a5
endm
head 6,LOBASE,lobase,xinfo,,reg_h ; LOBASE
dc.b mdAn
dc.b 3
use lobase
head 6,HIBASE,hibase,xinfo,,reg_h ; HIBASE
dc.b mdAn
dc.b 4
use hibase
head 7,MODBASE,modbase,xinfo,,reg_h ; MODBASE
dc.b mdAn
dc.b 5
use modbase
; Multiplication and division. In this version we dispense with all
; double length (64-bit) arithmetic. This is needed in 16-bit Forths,
; but hardly in a 32-bit system. Not in the nucleus, anyway. It is
; provided in the file LongMath. SM/REM and FM/MOD are defined there
; as well.
head 1,*,star,xinfo,,multdiv_h ; *
dc.w otMUL
star bra SMult ; NOP'd out if processor > 68000
pop.l d0
muls.l (a6),d0
move.l d0,(a6)
rts
head 2,*W,starW,xinfo,,multdiv_h ; *W
dc.w otMUL
starW pop.l d0
muls 2(a6),d0
move.l d0,(a6)
rts
head 1,//,slash,xinfo,,multdiv_h ; /
dc.w otDIV
slash bra pSlash ; NOP'd out if processor > 68000
pop.l d2
move.l (a6),d1
tdivs.l d2,d0:d1
move.l d1,(a6) ; Push quotient
rts
head 3,MOD,mod ; MOD
bra pMod ; NOP'd out if processor > 68000
pop.l d2
move.l (a6),d1
tdivs.l d2,d0:d1
move.l d0,(a6) ; Push remainder
rts
head 4,//MOD,slmod ; /MOD
bra pSlMod ; NOP'd out if processor > 68000
pop.l d2
move.l (a6),d1
tdivs.l d2,d0:d1
move.l d0,(a6) ; Push remainder
push.l d1 ; Push quotient
rts
head 5,U//MOD,uslmod ; U/MOD
bra pUSlMod ; NOP'd out if processor > 68000
pop.l d2 ; Divisor
move.l (a6),d1 ; Dividend
tdivu.l d2,d0:d1
move.l d0,(a6) ; Push remainder
push.l d1 ; Push quotient
rts
head 5,//MODW,slModW ; /MODW
bra pSlModW
head 6,//UMODW,uSlModW ; U/MODW
bra pUSlModW
; MulX is used to multiply a potentially longword index value by the width of
; each indexed element.
; D0 = index, D1 = width. Leaves result in D0. Uses D2.
head 4,MULX,mulx
bra pMulx ; NOP'd out if processor > 68000
mulu.l d1,d0
rts
; Copies of the original branches - used by Install to replace the branches
; before saving a new nucleus or application.
varbl 3,BRS,brs
dc.w $6000,sMult-star-2
dc.w $6000,pSlash-slash-2
dc.w $6000,pMod-mod-2
dc.w $6000,pSlMod-slMod-2
dc.w $6000,pUSlMod-UslMod-2
dc.w $6000,pMulx-mulx-2
; Note that */MOD and */ only use a 32-bit intermediate result.
; If you need 64 bits, load the file LongMath.
head 5,*//MOD,starslmod ; */MOD
move.l (a6)+,-(a7)
bsr star
move.l (a7)+,-(a6)
bra slMod
head 2,*//,starsl ; */
bsr.s starSlMod
pop.l (a6)
rts
; Shifts. << is now a synonym for ANSI LSHIFT, and >> for RSHIFT.
head 6,LSHIFT,Lshift,xinfo,,shift_h ; LSHIFT
dc.w otSHIFT*256
Lshift pop.l d0
pop.l d1
lsl.l d0,d1
push.l d1
rts
head 2,<<,.shiftL,xinfo,,shift_h ; <<
dc.w otSHIFT*256
.shiftL jmp Lshift-base(a3)
head 6,RSHIFT,Rshift,xinfo,,shift_h ; RSHIFT
dc.w otSHIFT*256 + 1
Rshift pop.l d0
pop.l d1
lsr.l d0,d1
push.l d1
rts
head 2,>>,.shiftR,xinfo,,shift_h ; >>
dc.w otSHIFT*256 + 1
.shiftR jmp Rshift-base(a3)
; ======================
; I/O
; ======================
valu 4,BUSY,busy ; BUSY
; FCB of file involved in asynchronous I/O, or zero if none.
; Set from high level, not from here. Cleared here though,
; by the completion routine.
valu 6,CPADDR,CPaddr,0 ; CPADDR
; Completion routine address, or zero if none. Also serves
; as a flag that the next op is to be asynchronous.
head 5,COMPL,compl ; COMPL
; Our completion routine for asynch I/O. We don't rely on
; any regs being set up. All we have to do is clear BUSY.
LEA busy,A0
CLR.L (A0)
RTS
head 5,SETCP,asynch ; SETCP
; Sets the completion routine address, making the next
; read or write asynchronous.
LEA compl,A0
MOVE.L A0,CPaddr-base(A3)
RTS
head 6,(MAKE),pmake ; (MAKE)
bra dopMake
head 6,(OPEN),popen ; (OPEN)
bra dopOpen
head 7,(CLOSE),pclose ; (CLOSE)
bra dopClose
head 8,(DELETE),.pdelete ; (DELETE)
bra dopDelete
head 6,(READ),pread ; (READ)
bra doPread
head 7,(WRITE),pwrite ; (WRITE)
bra doPwrite
head 7,(LSEEK),plseek
bra doPlseek
; ===========================
; OTHER SYSTEM CALLS
; ===========================
head 5,FINFO,.finfo ; FINFO
; ( -- addr )
; NOTE: This is only valid for systems where no AppleEvents are available.
; Therefore if they are available, we return a nil pointer.
tst.b AppleEventsQ+3-base(a3)
beq.s .fn1
push.l nilP
rts
.fn1 savA5
move.l $10(a5),a0
rstA5
push.l (a0)
rts
word0_m macrox
CLR.W -(A6)
endm
head 5,WORD0,word0,inline ; WORD0
zpack_m macrox
POP.L D0
ADDQ.L #2,A6
PUSH.W D0
endm
head 4,PACK,zpack,inline ; PACK
head 6,UNPACK,.unpk ; UNPACK
bra doUnpk
itol_m macrox
POP.W A0
PUSH.L A0
endm
head 4,I->L,itol,inline,tsCCOK ; I->L
makeint_m macrox
ADDQ.L #2,A6
endm
head 7,MAKEINT,makeint,inline ; MAKEINT
; Miscellaneous operations on handles and pointers. These
; are glue routines for various toolbox calls, which are
; needed by the HANDLE and PTR classes. They really should
; not be called directly from anywhere else.
head 4,NEWP,.newp ; NEWP
; ( n ^ptr -- b )
bra doNewP ; In nuc0.asm
head 4,NEWH,.newH ; NEWH
; ( n -- b )
bra doNewH ; In nuc0.asm
head 3,LOK,.lok ; LOK
bra doLok
head 5,UNLOK,.unlok ; UNLOK
; If the handle is nil, rather than trap, we treat it as a no-op.
; This simplifies each: handlelist and probably other things
; as well.
bra doUnlok
head 6,HGETST,.HGetSt ; HGetSt
; ( -- state )
bra doHgetst
head 6,HSETST,.HSetSt ; HSetSt
; ( state -- )
bra doHsetst
head 5,MVHHI,.mvHhi ; MvHHi
; ( -- b )
bra doMvHhi
head 5,KILLP,.killP ; KillP
bra doKillP
head 5,KILLH,.killH ; KillH
bra doKillH
head 5,COPYH,.copyH ; COPYH
; ( ^hdl -- n )
bra doCopyH
head 6,GETHSZ,.getHSz ; GETHSZ
; ( -- n )
bra doGetHsz
head 6,SETHSZ,.setHSz ; SETHSZ
; ( n -- b )
bra doSetHsize ; in Nuc0.asm
head 4,FREE,.free ; FREE
bra doFree
head 7,FREEBLK,.freeblk ; FREEBLK
bra doFreeBlk
head 6,?EVENT,qevent ; ?EVENT
bra doQevent
head 9,NEXTEVENT,nextEvent ; NEXTEVENT
; ( ^event mask -- b )
; We call WaitNextEvent if it's available, otherwise GetNextEvent.
bra doNextEvent
head 11,FIND-WINDOW,.fndwnd ; FIND-WINDOW
bra doFindWindow
head 4,BEEP,beep ; BEEP
savA5
ADDQ.L #2,SP
_SysBeep ; (duration:INTEGER)
rstA5
RTS
; ======= Support for :PROC and ;PROC ========
head 9,PROCENTRY,.procentry ; PROCENTRY
move.l saveEP,a0
jsr (a0)
head 8,PROCEXIT,procExit ; PROCEXIT
bra doProcExit
; =========================
; LOW-LEVEL STRING HANDLING
; =========================
head 4,FILL,fill ; FILL
POP.L D0
dofill POP.L D1
POP.L A0
MOVE.L D1,D2
SWAP D2
BRA.S .lptst
.loop MOVE.B D0,(A0)+
.lptst DBRA D1,.loop
DBRA D2,.loop
.end RTS
head 5,ERASE,erase ; ERASE
MOVEQ #0,D0
BRA.S dofill
head 6,BLANKS,.blanks ; BLANKS
MOVEQ #32,D0
BRA.S dofill
head 4,(S=),.pseq ; (S=)
; ( addr1 addr2 len -- b )
bra doPseq
head 2,S=,.seq ; S=
; ( addr1 len1 addr2 len2 -- b )
bra doSeq
head 4,MOVE,move ; MOVE
POP.L D0
POP.L A1
POP.L A0
_BlockMove
RTS
head 5,CMOVE,cmove ; CMOVE
POP.L D0
POP.L A1
POP.L A0
BRA.S .lptst
.loop MOVE.B (A0)+,(A1)+
.lptst DBRA D0,.loop
RTS
head 5,UPPER,upper ; UPPER
; ( addr len -- )
bra doUpper
; These words are used by the input parsing section.
; SCAN ( addr len c -- addr' len' ) searches the string ( addr len )
; for the character c. addr' is the address of the matching char,
; and len' is the remaining length (including the matching char). If no
; match, len' will be zero.
;
; Class String+ provides a more complete implementation in its
; chsearch: method, which has case handling and 32-bit length.
head 4,SCAN,scan ; SCAN
; ( addr len -- addr' len' )
bra doScan
head 4,SKIP,skip ; SKIP
bra doSkip
head 7,//STRING,slstring ; /STRING
; ( addr len n -- addr' len' )
pop.l d0
add.l d0,4(a6)
sub.l d0,(a6)
rts
; ==========================
; INPUT PARSING etc.
; ==========================
head 6,SOURCE,source ; SOURCE
; ( -- addr len )
move.l srcstart,d0
move.l toin,d1
add.l d1,d0
push.l d0
move.l srclen,d0
sub.l d1,d0
push.l d0
rts
head 8,SCAN-SRC,scansrc ; SCAN-SRC
; ( c -- ) Scans the input stream for delimiter c. Leaves the source
; updated to the next character, (so it could be empty if the found char
; was the last in the buffer) or overshot if none found (>IN exceeding
; SRC-LEN). The caller will need to check for this.
pop.l d2 ; Save char in D2
bsr.s source
push.l d2
bsr doScan
move.l srclen,d0
sub.l (a6)+,d0
addq.l #1,d0
move.l d0,toin-base(a3)
addq.l #4,a6
rts
head 8,SKIP-SRC,skipsrc ; SKIP-SRC
; ( c -- ) Skips consecutive delimiters equal to c in the source.
; Leaves source updated to the next character, or empty if none.
pop.l d2 ; Save char in D2
bsr source
push.l d2
bsr doSkip
move.l srclen,d0
sub.l (a6)+,d0
move.l d0,toin-base(a3)
addq.l #4,a6
rts
head 9,SKIP-SRC+,skipsrcpl ; SKIP-SRC+
; ( c -- ) Skips consecutive delimiters equal to c in the source.
; If the source gets exhausted before a non-c char is found, keeps
; calling REFILL to get more.
parms tor
.loop parms rat,skipsrc
move.l toin,d0
cmp.l srclen-base(a3),d0
blt.s .found
bsr doRefill
pop.l d0
bne.s .loop
n 154
bra die
.found ADDQ #4,A7
RTS
head 5,PARSE,parse ; PARSE
; ( c -- addr len ) Scans the source for delimiter c. Returns
; the addr and len of the parsed string, and updates the source
; to the remaining string.
move.l (a6),d1
move.l toin,(a6)
push.l d1
parms scansrc
move.l toin,d0
sub.l (a6),d0
subq.l #1,d0
move.l srcstart,d1
add.l d1,(a6)
push.l d0
rts
head 10,PARSE-WORD,parsewrd ; PARSE-WORD
; ( c -- addr len ) As for PARSE, but any consecutive initial
; delimiters are skipped. If the input is exhausted in the process,
; REFILL is called to get more.
parms dup,skipsrcpl,parse,semis
head 13,PARSE-DLM-STR,parseDlmStr ; PARSE-DLM-STR
; ( c -- addr len ) Scans the source for a string delimited at the
; start and end by c. Everything is skipped before the first delimiter.
; If the source gets exhausted in the process, REFILL is called to get more.
parms tor
.loop parms r,scansrc
move.l toin,d0
cmp.l srclen-base(a3),d0
blt.s .found
bsr doRefill
pop.l d0
bne.s .loop
n 154
bra die
.found parms rfrom,parse,semis
head 5,/$22STR/$22,qstrq ; "STR"
; ( -- addr len ) Scans for a string delimited by "..."
n $22
parms parseDlmStr,semis
head 5,PLACE,place ; PLACE
; ( addr1 len addr2 -- ) Converts string ( addr1 len )
; to a counted string at addr2. Appends a zero byte.
MOVE.L (A6),A0 ; A0 = addr2
MOVE.L 4(A6),D0 ; D0 = len
CLR.B 1(A0,D0.L) ; Append zero byte
MOVE.B D0,(A0) ; Store count byte
parms onep,swap,cmove,semis
wdLoc long
head 4,WORD,word ; WORD
; ( c -- addr ) Parses the source using
; c as the delimiter (using PARSE-SRC-WORD). Moves the resulting
; string as a counted string to HERE, and returns this address.
wd1 parms parsewrd
parms here,aligned
MOVE.L (A6),wdLoc-base(A3)
parms place
PUSH.L wdLoc
RTS
head 5,WORD",wordq ; WORD"
; ( -- addr )
n $22
BRA.S wd1
head 5,MWORD,mword ; MWORD
; ( -- addr ) "Mops word". Called by DEFINED? which is called
; by INTERPRET.
; Calls WORD with a blank as delimiter, and converts the string
; to upper case. Leaves counted string at addr (will be HERE).
parms bl,word,dup,count,upper,semis
head 4,/$2CSTR,comstr ; ,STR
; ( c -- ) c is delimiter. Adds the following text until delimiter
; to the dictionary as a counted string.
parms parse
comStr1
parms tuck,here,place,onep,aligned
parms allot,semis
head 8,/$2CDLM-STR,comDlmStr ; ,DLM-STR
; ( c -- ) Scans the source for a string delimited at the
; start and end by c, then adds it to the dictionary.
parms parseDlmStr
BRA.S comStr1
head 2,/$2C/$22,comq ; ,"
; Add text till " to the dictionary.
n $22
parms comstr,semis
head 6,/$2C/$22STR/$22,comqstrq ; ,"STR"
; Adds text delimited by " at the start and end.
n $22
parms comDlmStr,semis
head 9,(LIT-STR),plitstr,spec ; (LIT-STR)
; ( -- addr len )
; (LIT-STR) is called from any word that needs to be
; followed by a literal character string which has a
; length byte at the start.
; (LIT-STR) expects the top cell of the return stack
; to point to the length byte, and this cell is incremented
; to point to the next instruction following the string.
bra doPlitstr
nohead pquote,docol,,callStr_h ; (")
; Just compiles a normal call,
; but special handler code makes
; decompilation easier.
parms plitstr,semis
nohead pdotq,docol,,callStr_h ; (.")
parms plitstr
bsr type
parms semis
head $41,/$22,quote ; "
tst.l state-base(A3)
beq.s .intrp
compyl pquote
parms comq,pexit
.intrp n $22
parms parse,semis
head $42,S/$22,.Squote ; S"
bra.s quote ; ANSI synonym for "
head $42,./$22,.dotq ; ."
compyl pdotq
parms comq,semis
head $42,.(,.dotp ; .(
n $29
parms parse
JSR type-base(A3) ; Forward
parms semis
head $41,(,.lparen ; (
n $29
parms parse,twodrop,semis
head $41,\,.bslash,spec ; \
CLR.L srclen-base(A3)
RTS
; ======================
; SCREEN OUTPUT
; ======================
; We put some higher-level words first since they are
; vectored, and called by some of the lower-level words.
head 4,EMIT,emit ; EMIT
parms dup,emitvec,pemitvec
ADDQ.L #1,out-base(A3)
rts
head 10,EMITCYCLES,emitCycles ; EMITCYCLES
parms swap
n 0
qdo_m .end
.loop parms dup,emit
loop_m .loop
.end parms drop,semis
head 4,TYPE,type ; TYPE
parms dup
incVal out
parms twodup,typevec,ptypevec,semis
head 2,CR,cr ; CR
parms crvec,pcrvec,semis
head 5,SPACE,space ; SPACE
parms bl,emit,semis
head 6,SPACES,spaces ; SPACES
parms bl,emitcycles,semis
head 5,+ECHO,plecho ; +ECHO
ClrVect echovec
ClrVect emitvec
ClrVect typevec
ClrVect crvec
rts
head 5,-ECHO,mnecho ; -ECHO
setVect drop,echovec
setVect drop,emitvec
setVect twodrop,typevec
setVect null,crvec
rts
head 5,+CURS,plcurs,spec ; +CURS
MOVEQ #-1,D0
MOVE.L D0,curs-base(A3)
RTS
head 5,-CURS,mncurs,spec ; -CURS
zVal curs
RTS
; Now the low-level stuff:
head 4,HOME,home,spec ; HOME
savA5
gohome MOVE.L #$F0008,-(SP)
_MoveTo ; (h,v:INTEGER)
rstA5
RTS
head 3,CLS,cls,spec ; CLS
savA5
PEA FpRect
_EraseRect ; (r:Rect)
bra.s gohome
head 6,SCROLL,scroll ; SCROLL
bra DoScroll
head 7,>ORIGIN,ToOrigin ; >ORIGIN
savA5
MOVE.L (SP)+,D0
MOVE D0,(SP)
_SetOrigin ; (h,v:INTEGER)
rstA5
RTS
head 6,GOTOXY,gotoXY ; GOTOXY
savA5
MOVE.L (SP)+,D0
MOVE D0,(SP)
_MoveTo ; (h,v:INTEGER)
rstA5
RTS
head 3,@XY,atXY ; @XY
bra doAtXY
head 4,LINE,line ; LINE
savA5
MOVE.L (SP)+,D0
MOVE D0,(SP)
_Line ; (dh,dv:INTEGER)
rstA5
RTS
head 7,THEPORT,thePort ; THEPORT
savA5
MOVE.L (A5),A0
rstA5
PUSH.L (A0)
RTS
head 4,.CUR,dotcur,spec ; .CUR
savA5
bsr DrawCurs
rstA5
RTS
head 6,(EMIT),pemit ; (EMIT)
bra DoPemit
head 6,(TYPE),ptype ; (TYPE)
bra DoPtype
head 7,CONTBOT,contbot ; CONTBOT
parms thePort
add_m 160 ; $A0
parms wat,semis
head 7,CONTTOP,conttop ; CONTTOP
parms thePort
add_m 156 ; $9C
parms wat,semis
head 5,#LEAD,qlead ; #LEAD
bra DoQlead
head 6,#LINES,qlines ; #LINES
parms contbot,conttop,minus,qlead
parms slash,onem,semis
head 6,BOTTOM,bottom ; BOTTOM
parms qlead,qlines,onem,star
n 15
parms plus,conttop,plus,semis
head 4,(CR),pcr ; (CR)
bra DoPcr
head 4,(BS),pbs ; (BS)
bra DoPbs
; ===============================
; KEYBOARD INPUT
; ===============================
head 9,?TERMINAL,qterminal ; ?TERMINAL
n $28
parms qevent,semis
head 5,(KEY),pkey ; (KEY)
bra DoPkey
head 6,(KEY!),pkeyst ; (KEY!)
; Default for KEY!
SetVect pkey,key
parms plecho,plcurs,semis
AcceptLim long ; Saves length parameter passed to ACCEPT
head 6,ACCEPT,accept ; ACCEPT
bra DoAccept
head 10,SET_SOURCE,setsource ; SET_SOURCE
move.l tib,srcstart-base(a3)
move.l ntib-base(a3),srclen-base(a3)
clr.l toin-base(a3)
rts
head 5,QUERY,query ; QUERY
parms tib
n TIBlen
parms accept,drop,setsource
clr.l sourceID-base(a3)
rts
head 6,REFILL,refill ; REFILL
bra doRefill
; =====================
; NUMBER INPUT
; =====================
head 7,>NUMBER,toNumber ; >NUMBER
; ( ud1 addr1 len1 -- ud2 addr2 len2 )
bra doToNumber
head 9,?NOTFOUND,qnotfound ; QNOTFOUND
pop.l d0
bne.s .out
n -13
bra die ; "Undefined word"
.out rts
head 6,NUMBER,number ; NUMBER
bsr count
bsr doNumq
parms qnotfound,semis
head $47,LITERAL,literal ; LITERAL
callh hLiteral
RTS
; =============================
; NUMBER OUTPUT
; =============================
head 4,HOLD,hold ; HOLD
move.l hld,a0
pop.l d0
move.b d0,-(a0)
move.l a0,hld-base(a3)
rts
head 2,<#,bdigs ; <#
move.l pad,hld-base(a3)
rts
head 2,#>,edigs ; #>
bra doEdigs
head 4,SIGN,sign ; SIGN
bra doSign
head 1,#,dig ; #
bra doDig
head 2,#S,digs ; #S
.1 bsr doDig
tst.l 4(a6)
bne.s .1
rts
head 2,.R,dotr ; .R
bra doDotr
head 1,.,dot ; .
n 0
parms dotr,space,semis
head 2,U.,udot ; U.
bra doUdot
head 7,N>COUNT,ntocount ; N>COUNT
parms count
ANDI.B #$3F,3(A6)
rts
; ===========================
; DISK INPUT
; ===========================
; This is an interim scheme, used until the File class can be
; loaded. Thus it doesn't need to be very efficient.
head 5,!FPTR,stfptr ; !FPTR
; ( ^filename fcb -- )
add_m 18
parms store,semis
DiskBuf byte 10
head 6,(DKEY),pdkey ; (DKEY)
bra doPdkey
head 2,<",ltq ; <"
bra doLtq
head 3,-<",.mltq ; -<"
parms mnecho,ltq,semis
; =============================
; APPLEEVENTS
; =============================
head 9,AEHANDLER,AEhandler
; ( ^AE ^AEReply RefCon -- )
; Put at the start of an AppleEvent handler proc. Pops the parms into
; the appropriate locations.
bra doAEhandler
head 11,GOTPARMS?,GotParmsq
; ( -- rc )
; This can be called at the end of a handler, to check if we got all
; the parameters.
bra doGotParmsq
head 13,?RTNAEPMISSED,qRtnAEPmissed
; ( w:xx rc -- w:rc' )
; This can be called after calling GotParms? to convert the return code
; from that word to the appropriate return code to return to the caller
; of the handler. If GotParms? returns false, that means we missed
; a parm, so we return -1715. If GotParms? returned anything non-zero,
; that means we got all the parms, so we return zero.
tst.l (a6)+
beq.s .err
clr.w (a6)
rts
.err move.w #-1715,(a6) ; errAEParamMissed
rts
; ========================
; ERROR CHECKING
; ========================
head 5,CATCH,catch ; CATCH
bra doCatch
head 5,THROW,throw ; THROW
bra doThrow
; SAVE_ERR ( addr len -- ) saves all the info needed for an error dump, for use
; by the default error-interception routine, so that THROW can be called
; without our having to know if a non-default error-interception routine is
; installed or not. addr and len specifies an error text string.
head 8,SAVE_ERR,.svErr ; SAVE_ERR
bra doSvErr
; .ERR displays the error info saved by SAVE_ERR.
head 4,.ERR,dotErr ; .ERR
bra doDotErr
head 5,ABORT,abort ; ABORT
n 0
n 0
bsr doSvErr
n -1
bra doThrow
head 5,(AB/$22),pabq,docol,,callStr_h ; (AB")
bra doPabq
head $46,ABORT",.abortq ; ABORT"
JSR qcomp-base(A3) ; Forward
compyl pabq
parms comq,semis
svErrNum long
head 3,DIE,die ; DIE
move.l (a6),svErrNum-base(a3)
n -1 ; Indicates to SvErr that this is
bsr doSvErr ; an err#
push.l svErrNum
bra throwWithInfo
head 8,DFLT-ERR,dfltErr ; DFLT-ERR
bra doDfltErr
head 5,?COMP,qcomp ; ?COMP
move.l state,d0
bne.s qcOut
n -14
bra die ; "Interpreting a compile-only word"
qcOut rts
head 6,?STACK,qstack ; ?STACK
bra doQstack
head 5,?EXEC,qexec ; ?EXEC
move.l state,d0
beq.s qcOut
n 77
bra die ; "Execution state only"
head 6,?PAIRS,qpairs ; ?PAIRS
pop.l d0
sub.l (a6)+,d0
beq.s qprsOut
n -22
bra die ; "Control structure mismatch"
qprsOut rts
head 5,?DEFN,qdefn ; ?DEFN
pop.l d0
sub.l (a6)+,d0
beq.s qprsOut
n 78
bra die ; "Unbalanced definition"
head 4,$CHK,.strchk ; $CHK
; Checks the current string object for legality.
; Checks that POS and LIM are within the string, and that
; POS is not past LIM. A2 points to the string object.
; The offsets are:
;
; 4 size of string (long)
; 8 POS (long)
; 12 LIM (long)
MOVE.L 4(A2),D0 ; D0 = size
CMP.L 8(A2),D0
BLO.S strFail ; Unsigned chk means negative will fail too,
CMP.L 12(A2),D0 ; which is what we want
BLO.S strFail
LEA 8(A2),A0
CMPM.L (A0)+,(A0)+
BLO.S strFail
RTS
head 5,$FAIL,strFail ; $FAIL
PUSH.L 12(A2) ; Push LIM
PUSH.L 8(A2) ; Push POS
PUSH.L 4(A2) ; Push SIZE
ExVec strErr ; Forward - vector
_debugger ; We shouldn't get here?!
; =====================================
; DICTIONARY OPERATIONS
; =====================================
; Note: , w, and c, don't change D0, A0 or A1. IN HANDLERS WE RELY ON THIS.
head 1,/$2C,comma ; ,
MOVE.L A0,-(A7)
MOVE.L DP-base(A3),A0
MOVE.L (A6)+,(A0)
ADDQ.L #4,DP-base(A3)
MOVE.L ODaddr,A0
CLR.W (A0)
MOVE.L (A7)+,A0
RTS
head 2,W/$2C,wcomma ; W,
MOVE.L A0,-(A7)
MOVE.L DP-base(A3),A0
POP.L D1
MOVE.W D1,(A0)
ADDQ.L #2,DP-base(A3)
MOVE.L ODaddr,A0
CLR.W (A0)
MOVE.L (A7)+,A0
RTS
head 2,C/$2C,ccomma ; C,
MOVE.L A0,-(A7)
MOVE.L DP-base(A3),A0
POP.L D1
MOVE.B D1,(A0)
ADDQ.L #1,DP-base(A3)
MOVE.L ODaddr,A0
CLR.W (A0)
MOVE.L (A7)+,A0
RTS
head 2,N/$2C,ncomma ; N,
parms tor,here,r,cmove,rfrom,allot
parms semis
head 5,ALIGN,align ; ALIGN
move.l dp-base(a3),d0
moveq #1,d1
and.b d0,d1
add.l d1,d0
move.l d0,dp-base(a3)
rts
; Align-DP is a synonym for backwards compatibility.
head 8,ALIGN-DP,alignDP ; ALIGN-DP
bra align
head 8,(FORGET),pforget ; (FORGET)
; ( lfa -- )
bra doPforget
head 6,FORGET,.forget ; FORGET
JSR tick-base(A3) ; Fwd ref
parms tolink,pforget,semis
; ================================
; CONVERSION BETWEEN RELATIVE AND
; ABSOLUTE ADDRESSES
; ================================
; head 4,>B&D,toBandD ; >B&D
; ( addr -- breg displ )
; Uses D0,D1 and A1. Doesn't use A0 as caller needs it.
; Leaves module's addressing base in A1, if any.
; Leaves breg in D1.
; bra doToBandD
head 8,>B&DCOMP,.toBandDcomp ; >B&DCOMP
; Used by the assembler when generating a b-d address. The
; client's modbase value is in MBcomp, so we use that instead
; of the current A5.
bra doToBandDComp
noRelChk
dc.b 0
noAbsErr
dc.b 0
align
head 6,RELOC!,relocSt ; RELOC!
; ( src dst -- ) Converts the src addr to relocatable and
; stores it in the destination.
bra doRelocSt
head 6,RELOC/$2C,relocComma ; RELOC,
parms here,relocSt
n 4
parms allot,semis
pAtAbs bra doPAtAbs
head 4,@ABS,atAbs ; @ABS
; ( ^reloc-addr -- abs-addr )
move.l (a6),a0
bsr doPAtAbs
move.l a0,(a6)
rts
head 9,RELOCTYPE,.relocType ; RelocType
; ( ^reloc-addr - n )
; Returns the relocation type of the given relocatable addr.
; 0 = main dic, 1 = in a module (a5-relative), 2 = in a module (self-relative).
bra doRelocType
head 8,DISPLACE,displace ; DISPLACE
; ( addr -- addr' )
MOVE.L (A6),A0
MOVE.L (A0),D0
BEQ.S dplnone
ADD.L D0,(A6)
RTS
dplnone CLR.L (A6)
RTS
head 9,WDISPLACE,.Wdisplace ; WDISPLACE
; ( addr -- addr' )
MOVE.L (A6),A0
MOVE.W (A0),D0
BEQ.S dplnone
EXT.L D0
ADD.L D0,(A6)
RTS
head 6,DISPL!,.displSt ; DISPL!
; ( src dst -- ) Stores the source address as a relative
; address at the destination.
pop.l a0
pop.l d0
sub.l a0,d0
move.l d0,(a0)
rts
head 7,WDISPL!,.WdisplSt ; WDISPL!
; ( src dst -- ) Stores the source address as a short relative
; address at the destination (it is relative to the destination).
pop.l a0
pop.l d0
sub.l a0,d0
move.w d0,(a0)
rts
head 6,DISPL/$2C,.displCom ; DISPL,
; ( src -- )
move.l dp,d0
sub.l d0,(a6)
parms comma
rts
; ==================================
; GLUE WORDS INTERFACING TO HANDLERS
; ==================================
head 8,COMPCALL,.compCall ; CompCall
jumph call_h
head 7,DEFNEND,.defnEnd ; DefnEnd
jumph hDefnEnd
head 8,LIT-ADDR,.litAd ; LIT-ADDR
jumph litAddr
head 7,GENADDR,.genaddr ; GENADDR
jumph hgenaddr
head 8,GENXADDR,.genxaddr ; GENXADDR
jumph hgenxaddr
head 6,LOADBA,.loadBA ; LoadBA
jumph hLoadBA
head 6,MENTRY,.Mentry ; Mentry
jumph hmentry
head 7,PLENTRY,.plentry ; PLENTRY
jumph hplentry
head 2,EB,.EB ; EB
jumph heb
head 6,STKOBJ,.EBstk ; STKOBJ
jumph hStkObj
head $42,EX,.ex ; EX
jumph hDoEx
head 7,(PATCH),.ppatch ; (PATCH)
callh hPatch
bra patchesDone
; head 6,CALLBA,.callBA ; CallBA
; jumph hCallBA
; LocParm and FlocParm are dummy words whose cfa is returned by FIND if the
; symbol is a parameter or local variable. (FlocParm is used for floating
; quantities). When we then try to compile this word, its handler LOC_H
; or FLOC_H is called, which does all the real work. It picks up the
; lv/p number from LOC# (where it was put by PFind) and compiles the right
; code.
head 7,LOCPARM,.locparm,nocode,,loc_h
; and we don't need anything here!!
head 8,FLOCPARM,.flocparm,nocode,,Floc_h
head 7,COMPIMP,.compImp ; CompIMP
jumph hcompimp
head 8,COMPFPUL,.compFPUL ; CompFPUL
jumph hcompFPUL
; ========================================
; LOW-LEVEL SUPPORT FOR VARIOUS CONSTRUCTS
; ========================================
head 5,(SEL),.psel ; (SEL)
pop.l d0 ; D0 = index
move.l (a7),a0 ; Return addr
move.w (a0),d1 ; D1 = offset to end of table
add.w d1,a0 ; Update RA
move.l a0,(a7) ; and store back
cmp.w -2(a0),d0
bls.s .ps1
.psDf moveq #-1,d0 ; Use default
.ps1 add.w d0,d0
neg.w d0
move.w -6(a0,d0.w),d1 ; Get offset to action stub, using index
jmp 0(a0,d1.w) ; Away we go. Don't change this
; instruction or the debugger won't
; like it.
; Module entry
head 8,MODENTRY,modentry ; MODENTRY
; D2 = entry point index
; A1 = addr of module object
bra doModEnt
head 10,?UNHOLDMOD,.qUnHoldMod
bra doQUnHoldMod
head 5,EBMOD,EBmod
bra doEBmod
; ==================================
; DICTIONARY LOOKUP
; ==================================
boffs long
hashval long
pFindmRunning ; Set NZ while (findm) is running, so we can give
byte ; a proper error message if we get an illegal
; relocatable address.
pFindRunning
byte ; Similarly for Find, if an odd addr trap occurs.
align
head 6,THREAD,thread ; THREAD
; ( str-addr -- thread-addr )
bra doThread
head 6,(FIND),pfind ; (FIND)
; ( string-addr lfa -- cfa flag | -- string-addr false )
; lfa points to the dictionary entry where the search is to start.
; Note this definition is changed from Neon.
bra DoPfind
head 7,(FINDM),.pfindm ; (FINDM)
; ( hash ^class link-offs -- offs cfa T | F )
bra DoPfindM
head 4,FIND,find ; FIND
; ( str-addr -- cfa flag | -- F )
bra doFind
head 5,SFIND,sFind ; SFIND
; ( addr len -- addr' n )
parms pad,place,pad,count,upper
parms pad,find,semis
head 8,DEFINED?,defined ; DEFINED?
parms Mword
bra doFind
head 1,',tick ; '
parms defined,qnotfound,semis
head $43,['],btick ; [']
parms tick
jumph LitAddr
;
; LFA is 8 -
; NFA is 9 - -1 traverse
; PFA is 1 traverse 9 +
;
; =============================
; COMPILATION
; =============================
saveTandS word
whichCFA long
; Patches_done is called after any new instructions have been stored, or
; patches have been done, and before the instructions are executed. It
; flushes the instruction cache if necessary.
; 68030 (and later) chips have an instruction and data cache. If we
; write a new instruction into a location, the 680x0 thinks it was a data
; access. The data cache is correctly updated, but not the instruction
; cache. Then if we try to execute the new instruction too soon, we may
; get the old contents of that location from the instruction cache instead.
; There are several situations where this could happen, such as when we do
; EX-GEN. The solution is to flush the instruction cache whenever we may be
; changing instruction locations where we may have previously been executing.
; The Mac OS has a trap (_HWpriv with opcode 1) to do this, but it is only
; present on the chips which need it. Accordingly we check on startup if this
; trap is present, and set a flag accordingly. FlushCache calls the trap if
; it is there, and otherwise just returns (no cache to flush, so no problem).
head 12,PATCHES_DONE,patchesDone ; PATCHES_DONE
FlushCache ; Old name - outrageous computerese
TST.B HWPavail+3-base(A3)
BEQ.S .out ; Out if HWPriv trap not available
MOVEQ #1,D0 ; Code 1 means flush the instrn cache
exg a6,a7
dc.w $A198 ; HWPriv trap
exg a6,a7
.out RTS
; (COMP) ( cfa -- ) Compiles the word with the given cfa, by
; calling its compilation handler. All compilation should be done
; via this word or (COMPN), since they properly allow for words with
; optimization etc. This word assumes a zero opcode is to be passed
; to Handlers. If not, use (COMPN).
head 6,(COMP),pcomp ; (COMP)
bra doPcomp
; ANSI synonym:
head 8,COMPILE/$2C,.compComma ; COMPILE,
bra doPcomp
; (COMPN) ( cfa n -- ) is similar to (COMP), but has an additional
; parameter n which is the opcode for -> ++> etc.
head 7,(COMPN),pcompn ; (COMPN)
pop.l whichCFA-base(a3)
bra pcomp1
head $41,[,lbrack,spec ; [
; Note - immediate so not inline.
zVal state
RTS
head $41,],rbrack,spec
moveq #-1,d0
move.l d0,state-base(a3)
rts
head $49,IMMEDIATE,.immediate ; IMMEDIATE
n $40
PUSH.L latest-base(A3) ; Forward ref
parms cset,semis
; In this system, compilation is done by executing the compilation handler
; for the word in question. POSTPONE must therefore be immediate, and
; compile the right code into the client definition. This code consists
; of a literal push of the POSTPONEd word's cfa, then a call to (COMP).
head $48,POSTPONE,.postpone ; POSTPONE
parms defined
TST.L (A6)+
BLT.S .nonimmed
BGT pcomp
n 0
parms qnotfound
.nonimmed
callh LitAddr
compyl pcomp
RTS
; ================================
; INTERPRETATION
; ================================
; In our native code/STC system, interpreting a word is slightly non-trivial.
; We provide two types of execution. EXECUTE simply JMPs to
; the given cfa. This will work for many words, but not all. For the
; general case we provide another execution word EX-GEN (execute general)
; which compiles the word in a separate buffer, plants a
; jump at the end, then branches to the start. The jump at the end
; goes to ChkOK which checks the stack before returning. EX-GEN is
; slower than EXECUTE, but will execute anything. For this reason
; it is called by INTERPRET. But note, EX-GEN can't be called from an
; installed application, since it causes compilation to occur.
head 7,EXECUTE,execute ; EXECUTE
; ( cfa -- )
pop.l a1
bra inlck
head 9,EX-METHOD,.exMethod ; EX-METHOD
; ( ^obj cfa -- )
bra doExMethod
ExBuf byte 100
chkOK bra doChkOK
xJsrBak jsr chkOK-base(A3)
head 6,EX-GEN,exgen ; EX-GEN
; ( cfa -- )
bra doExGen
; EXN ( cfa n -- ) is to EX-GEN what (COMPN) is to (COMP). It
; has the additional parameter n which is action code for -> ++> etc.
; Because this can be called from EX-GEN (which may be executing a prefix
; op), we use the alternate execution buffer ExBuf1.
head 3,EXN,exN ; EXN
lea pcompn,A0
bra exgen1
; INTERPRET is the interpretation loop. Words from the input stream are
; interpreted until the input is exhausted.
head 9,INTERPRET,interpret ; INTERPRET
bra doInterpret
head 6,INTRP1,intrp1 ; INTRP1
; ( addr -- ?? ) Interprets one word/number from the input stream.
parms defined
tst.l (a6)+
beq.s .trynum
bra doExGen
.trynum parms number,semis
head 2,OK,ok ; OK
bra doOK
head 4,QUIT,quit ; QUIT
bra doQuit
; ================================
; DEFINING WORDS
; ================================
head 8,(HEADER),pheader ; (HEADER)
bra doPheader
head 4,SHDR,sHdr ; SHDR
; ( addr len -- ) Creates a header for the passed-in string.
bra doSHdr
head 6,CREATE,create ; CREATE
parms header
comh create_h
RTS
head 7,SCREATE,sCreate ; SCREATE
parms sHdr
comh create_h
RTS
head 10,CREATE_OBJ,createObj ; CREATE_OBJ
parms header
comh obj_h
RTS
head $44,HIDE,hide ; HIDE
; Hides the name of the current definition from dic searches.
PUSH.L latest-base(A3) ; Forward ref
parms dup,ntolink,displace
hide1 parms swap,thread
parms tuck,minus
parms swap,store,semis
head $46,REVEAL,reveal ; REVEAL
; Makes the current name visible again.
PUSH.L latest-base(A3) ; Forward ref
parms dup,ntolink
BRA.S hide1
head 6,COLHDR,colHdr ; COLHDR
; Lays down the header for a colon definition.
parms header
comh col_h
RTS
; :NONAME does the work for : once the header has been laid down.
; It is also called from other words that begin definitions
; such as :proc.
head 7,:NONAME,colNoname ; :NONAME
parms qexec
move.l DP,currDef-base(a3)
clr.b fmkCnt-base(A3)
clr.b callOut-base(A3)
parms rbrack,semis
head $41,:,colon ; :
parms colHdr,hide,colNoname
n 300
rts
head 7,CLRCOMP,clrComp ; CLRCOMP
zVal numPL
zVal methodq
clr.l FltFlg-base(a3)
sf colaFlg-base(a3)
; ** zero any other flags here!!
NoOpt
RTS
head 3,(/$3B),psemip ; (;)
callh CompExit
tst.b localq+3-base(A3)
bne.s .sem1
bsr.s clrComp
.sem1 parms lbrack,reveal,semis
head $41,/$3B,.semi ; ;
parms psemip
n 300
parms qdefn,semis
head $42,:A,.colA ; :A
parms colHdr
callh hColA
parms colNoname
n 310
rts
head $42,/$3BA,.semiA ; ;A
parms psemip
n 310
parms qdefn,semis
head 4,CODE,.code ; CODE
BRA colHdr
; ================
head 8,CONSTANT,.constant ; CONSTANT
parms header
comh const_h
parms comma,semis
head 5,VALUE,.value ; VALUE
parms header
comh val_h
parms comma,semis
head 6,OBJPTR,.objPtr ; OBJPTR
parms header
comh objptr_h
parms nilP,comma
n 0
parms comma,semis
; ======= Vectors =======
xjsrExVect
jsr DoExVect-base(a3)
xjsrToVect
jsr DoToVect-base(a3)
DoExVect
move.l (a7)+,a0
tst.l (a0)
beq.s .evDflt
bsr doPAtAbs
jmp (a0)
.evDflt jmp 4(a0)
DoToVect
tst.l (a6)
beq.s .tvDflt
bra rlSt1 ; Dest addr is in A0 already
.tvDflt clr.l (a0)
addq #4,a6
rts
head 4,VECT,.vect ; VECT
parms header
comh vect_h
push.l xJsrExVect
parms comma,here
n 0
parms comma
pop.l a0
bra.s DoToVect
head 8,VARIABLE,.variable ; VARIABLE
parms create
n 0
parms comma,semis
; -> (immediate, compilation only) compiles a store to a value
; or a vect by passing the otStore opcode to its compilation handler.
; This is an interim scheme until -> is redefined in the file Args.
head $42,->,.to ; ->
n otStore
to1 parms qcomp,tick,swap,pcompn,semis
; ++> compiles an increment to a value.
head $43,++>,.plto ; ++>
n otAdd
BRA.S to1
; We retain <BUILDS to be used in conjunction with DOES> rather
; than following the standard and using CREATE. This is because
; CREATEd words have the data right at the cfa,
; while DOES> words have to have a pointer to the DOES> code. So rather
; than waste space in CREATEd words or do a complicated kludge during
; compilation, we use <BUILDS.
; To compile a call to a DOES word, we first compile a LEA to the Child's
; pfa, then JSR to the DOES code. At the beginning of the DOES code we
; compile a push of A0 to the stack.
head 7,<BUILDS,.builds ; <BUILDS
parms header
comh builds_h
n 0
parms comma,semis ; Will be patched by DODOES
nohead dodoes ; dodoes
parms rfrom
push.l latest-base(a3)
parms namefrom
move.l (a6),a0
moveq #does_h,d0 ; Change handler to does_h
move.w d0,-2(a0)
parms relocst,semis
head $45,DOES>,.does ; DOES>
compyl dodoes
callh FixDoes
rts
; ==================================
; CONTROL STRUCTURES
; ==================================
; We use various devious means to generate short branches in most cases
; where these are possible. The cases where we don't are:
;
; 1. The forward BRA compiled by ELSE. When we get to THEN we resolve this,
; and we don't find out until then that it could be short. If we then changed
; it, we would also need to change the branch offset compiled by IF
; (reducing it by 2). We would need a new mechanism for keeping track of
; where this branch is, which probably isn't worth the bother, especially
; as a taken branch takes the same number of cycles on a 68000 regardless
; of whether it is short or long.
;
; 2. Any basic block that contains a short BSR to another word, we don't
; allow to be moved, since we don't want to keep track of the location of
; such BSRs. Thus we don't shorten a branch that immediately
; precedes such a block. If the distance was too great for a short BSR, we
; use a JSR, if we can, since this can be moved with no problem.
;
; This arrangement may not be absolutely optimum, but without a horrendous
; multi-pass compilation it's about the best we can do - and it's not really
; all that bad, anyway.
; Note that we must explicitly block optimization at <MARK and >RESOLVE since
; two control paths are joining. We needn't bother at >MARK and <RESOLVE
; since a branch is always compiled which will block optimization anyway.
bran BRA .dummy
qbran TST.L (A6)+
BNE .dummy
zbran TST.L (A6)+
BEQ .dummy
nohead compbr ; compbr
MOVE.W bran,D0
PUSH.L D0
parms wcomma
RTS
.dummy
nohead chkCCmp
; ( -- n )
MOVEQ #0,D0
MOVE.B CCmpFlg,D0
CLR.B CCmpFlg-base(A3)
PUSH.L D0
RTS
head 5,>MARK,fmark ; >MARK
ADDQ.B #1,fmkCnt-base(A3)
parms chkCCmp,here
n 120
TST.L 8(A6)
BEQ.S .1
parms pexit
.1 n 0
parms wcomma,semis
head 5,<MARK,bmark ; <MARK
NoOpt ; Mustn't optimize here
parms here
n 121
parms semis
frBrAd long
head 8,>RESOLVE,fresolve ; >RESOLVE
bra doFresolve
head 9,>RESOLVEN,fresolveN ; >RESOLVEN
ADDQ.B #1,callOut-base(A3)
bsr doFresolve
SUBQ.B #1,callOut-base(A3)
RTS
brsSh byte
align
head 8,<RESOLVE,bresolve ; <RESOLVE
bra doBresolve
head $42,IF,zif ; IF
parms true
if1 callh pif
parms fmark,semis
head $43,NIF,nif ; NIF
parms false
BRA.S if1
head $44,ELSE,.zelse ; ELSE
bra doElse
head $44,THEN,then ; THEN
bra doFresolve
head $45,BEGIN,.begin ; BEGIN
parms bmark,semis
head $45,WHILE,.while ; WHILE
parms zif,semis
head $46,NWHILE,.nwhile ; NWHILE
parms nif,semis
head $45,UNTIL,.until ; UNTIL
parms true
until1 callh pif
bra doBresolve
head $46,NUNTIL,.nuntil ; NUNTIL
parms false
BRA.S until1
head $45,AGAIN,again ; AGAIN
parms compbr
bra doBresolve
head $46,REPEAT,.repeat ; REPEAT
bra doRepeat
head $42,DO,.do ; DO
compyl pdo
do1 SUBQ.L #6,DP-base(A3)
parms fmark
ADDQ.L #4,DP-base(A3)
parms bmark,semis
head $43,?DO,.qdo ; ?DO
compyl pqdo
BRA.S do1
nohead fixLoop ; fixLoop
SUBQ.L #6,DP-base(A3)
bsr doBresolve
PUSH.L windupDo-base(A3)
parms comma,fresolve,semis
head $44,LOOP,.loop ; LOOP
compyl ploop
parms fixLoop,semis
head $45,+LOOP,.plloop ; +LOOP
callh CompPlLoop
parms fixLoop,semis
xLvJmp JMP DoLeave-base(A3)
head $45,LEAVE,.leave ; LEAVE
PUSH.L xLvJmp
parms comma
RTS
head 6,UNLOOP,.unloop ; UNLOOP
MOVE.L (A7)+,A0 ; Return address
ADDQ.L #8,A7 ; Pop limit and loop end address
MOVE.L (A7)+,D3 ; Restore old i
JMP (A0)
; FOR ... NEXT as per Charles Moore. This allows us to use DBRA and
; so is very fast.
head $43,FOR,.for ; FOR
PUSH.L .DoFor
parms comma
compop .doSubq
parms bmark
RTS
.DoFor MOVE.L D3,-(A7)
POP.L D3
.DoSubq SUBQ.W #1,D3
head $44,NEXT,.znext ; NEXT
n 121
parms qpairs
compop .xDBRA
POP.L D1 ; Saved DP value
SUB.L dp,D1
PUSH.L D1
parms wcomma
compop .fixNext
RTS
.xDBRA DBRA D3,.dummy ; Dummy destination
.fixNext
MOVE.L (A7)+,D3
.dummy
; EXIT etc.
head $44,EXIT,.exit ; EXIT
jumph CompExit
head $45,?EXIT,.qexit ; ?EXIT
parms zif
qex1 callh CompExit
parms then,semis
head $45,0EXIT,.zexit ; 0EXIT
parms nif
BRA.S qex1
; =================================
; STACK DUMPING, ETC.
; =================================
nohead dotval ; .val
parms dotr
n 2
parms spaces,semis
nvec sPrint
_debugger ; Catch if uninitialized
head 5,NAME?,nameq ; NAME?
; ( addr -- addr b )
parms dup,toName,NtoCount
parms plus,aligned,twop,over,eq
RTS
; CFA? ( cfa? -- cfa? b ) Checks if cfa? could really be a CFA.
head 4,CFA?,cfaq ; CFA?
; ( addr -- addr b )
bra doCfaq
head 6,CLASS?,classq ; CLASS?
; ( cfa -- cfa b )
; Returns true if the cfa refers to a class.
bra doClassq
theClass long
theObj long
head 8,OBJFINDM,.objFindM ; ObjFindM
; ( selID ^obj -- ^obj' cfa )
; Finds a method's cfa given a sel ID and an obj addr.
; Updates the object's address if necessary - this will happen if the
; method turns out to belong to a superclass with a non-zero offset
; in the object - i.e. an embedded object.
bra doObjFindM
head 7,OBJCFA?,objcfaq ; OBJCFA?
; ( cfa -- cfa b )
; Returns true if the cfa refers to a dictionary object.
; Note: this won't work for a heap object, since we rely on
; the unique handler code for objects being there, and it won't
; be for heap objects. But this is the only way to get a really
; rigorous check, which we need for TRAV. We assume cfa is
; really a cfa.
bra doObjCfaq
head 6,>CLASS,toClass ; >CLASS
; ( ^obj -- ^class | -- 0 )
; Converts an object address to its class address. Returns zero if the passed-in
; address isn't an object address. Needs to work for heap as well as dictionary
; objects. The test is very unlikely (maybe 1/2**24) to
; indicate a non-object as being an object. Without tagged storage we can't
; be absolutely sure. To save time we don't do a conservative check on ^obj
; actually being a legal address (unlike CFA?), apart from checking that it is
; even, which is a very quick check. This means we may crash if an even but illegal
; address is passed in. The presumption is that it really is an object address,
; and that anything else is an (unlikely) error.
bra doToClass
head 9,>CLASSCFA,.toClassCfa ; >ClassCfa
; ( ^obj -- ^class | -- 0 )
; As for >CLASS, but if the class is exported from a module and
; you are executing in the main dictionary, it gives the cfa of
; the imported word, without accessing the module. This can be useful
; if you just want to identify a class without needing all the class info.
; If you are executing in the module, however, you will get the cfa of
; the class in the module. The general rule is that the returned cfa will
; always be the same as if you had just ticked the classname, wherever you
; are executing. As for >CLASS, zero is returned if the passed-in address
; doesn't point to an object.
moveq #0,d2
bra toClass1
head 12,?>CLASSINMOD,.qtoclassInMod ; ?>ClassInMod
; ( ^class -- ^class' )
; Converts a class address to the corresponding class address in a module,
; if the class is exported, and holds the module. If the class isn't
; exported, does nothing.
bra doQtoClassInMod
head 4,OBJ?,objq ; OBJ?
; ( ^obj? -- ^obj? ^class | -- ^obj? 0 )
; General test for an object. Not completely rigorous, so we
; shouldn't use it in a TRAV, but pretty good nevertheless. If it is
; an object, the class is left in theClass. We do assume the passed-in
; value may not be a legal address at all.
bsr cfaq
tst.l (a6)
beq.s .no
move.l 4(a6),(a6)
bra doToClass
.no rts
TheCFA long
head 3,RA?,raq ; RA?
; ( addr -- b )
bra doRAq
head 3,.ID,dotid ; .ID
; ( ?cfa -- )
parms cfaq
TST.L (A6)+
BEQ.S .notCfa
parms nameq
TST.L (A6)+
BEQ.S .noName
parms toname,NtoCount,type,pexit
.noName msg (no name)
.notCfa parms drop,semis
nohead dotObjOrRA ; .objOrRA
; ( addr -- )
bra doDotObjOrRA
head $42,DB,.debugger ; DB
n $a9ff
parms wcomma,semis
head 4,(.S),.pDotS ; (.S)
; ( end-addr strt-addr -- )
move.l #1000,d1
bra pDotStk
head 2,.S,dots ; .S
bra doDots